package cz.muni.fi.pa036is.servicesimplementation;

import cz.muni.fi.pa036is.utilities.ScoreCalculationService;
import cz.muni.fi.pa036is.daointerface.AddressDAO;
import cz.muni.fi.pa036is.daointerface.AdmissionDAO;
import cz.muni.fi.pa036is.daointerface.MatchDAO;
import cz.muni.fi.pa036is.daointerface.PersonDAO;
import cz.muni.fi.pa036is.daointerface.RoundDAO;
import cz.muni.fi.pa036is.daointerface.SeasonDAO;
import cz.muni.fi.pa036is.dto.AddressTO;
import cz.muni.fi.pa036is.dto.AdmissionGridTO;
import cz.muni.fi.pa036is.dto.MatchGridTO;
import cz.muni.fi.pa036is.dto.PersonBasicTO;
import cz.muni.fi.pa036is.dto.PersonDetailTO;
import cz.muni.fi.pa036is.dto.PersonFormTO;
import cz.muni.fi.pa036is.dto.PersonGridTO;
import cz.muni.fi.pa036is.dtoconverters.AddressConverter;
import cz.muni.fi.pa036is.dtoconverters.AdmissionConverter;
import cz.muni.fi.pa036is.dtoconverters.MatchConverter;
import cz.muni.fi.pa036is.dtoconverters.PersonConverter;
import cz.muni.fi.pa036is.entity.Address;
import cz.muni.fi.pa036is.entity.Admission;
import cz.muni.fi.pa036is.entity.Match;
import cz.muni.fi.pa036is.entity.Person;
import cz.muni.fi.pa036is.entity.Season;
import cz.muni.fi.pa036is.servicesinterface.PersonService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * @author Shebik
 */
@Service
public class PersonServiceImpl implements PersonService{

    @Autowired
    private PersonDAO personDAO;

    @Autowired
    private AddressDAO addressDAO;

    @Autowired
    private AdmissionDAO admissionDAO;

    @Autowired
    private MatchDAO matchDAO;

    @Autowired
    private SeasonDAO seasonDAO;

    @Autowired
    private RoundDAO roundDAO;

    @Autowired
    private ScoreCalculationService scoreCalculationService;

    @Override
    public void addPerson(PersonFormTO personFormTO) {
        final Person person = PersonConverter.convertToPerson(personFormTO);
        final Address address = AddressConverter.convertToAddress(
                personFormTO.getAddress());
        personDAO.addPerson(person);        //todo - overit ci nastavi do person vygenerovane id
        address.setPersonId(person.getId());
        addressDAO.addAddress(address);
								
								personFormTO.setId(person.getId());
    }

    @Override
    public void editPerson(final PersonFormTO personFormTO) {
        final Person person = PersonConverter.convertToPerson(personFormTO);
        final Address address = AddressConverter.convertToAddress(
                personFormTO.getAddress());
        address.setPersonId(person.getId());
        personDAO.editPerson(person);
        addressDAO.editAddress(address);
    }

    @Override
    public void deletePerson(final Long personId) {
        if (!matchDAO.getAllMatchesForPerson(personId).isEmpty()) {
            throw new IllegalStateException("The person with id="+ personId
                    + " has some related match records so it cannot be deleted.");
        }
         //todo - je vhodne mazat zaznamy o poplatkoch?
        for (final Admission admission : admissionDAO.findAdmissionsForPerson(personId)) {
            admissionDAO.deleteAdmission(admission);
        }
        addressDAO.deleteAddress(personId);
        personDAO.deletePerson(personId);
    }

    @Override
    public PersonFormTO getPersonForm(Long id) {
        final PersonFormTO personFormTO = PersonConverter.convertToPersonFormTO(
                personDAO.findPerson(id));
        final AddressTO addressTO = AddressConverter.convertToAddressTO(
                addressDAO.getAddressByPerson(id));
        personFormTO.setAddress(addressTO);
        return personFormTO;
    }

    @Override
    public PersonDetailTO getPersonDetail(final Long id) {
        final PersonDetailTO personDetailTO = PersonConverter.convertToPersonDetailTO(
                personDAO.findPerson(id));
        final AddressTO addressTO = AddressConverter.convertToAddressTO(
                addressDAO.getAddressByPerson(id));
        personDetailTO.setAddress(addressTO);
        personDetailTO.setAdmissionList(convertToAdmissionGridTOList(
                admissionDAO.findAdmissionsForPerson(id)));
        personDetailTO.setMatchList(convertToMatchGridTOList(
                matchDAO.getAllMatchesForPerson(id)));
        return personDetailTO;
    }

    @Override
    public List<PersonGridTO> getAllPersons() {
        return PersonConverter.convertToPersonGridTOList(personDAO.getAllPersons());
    }

    @Override
    public List<PersonBasicTO> getAllPersonsForDropDown() {
        return PersonConverter.convertToPersonBasicTOList(personDAO.getAllPersons());
    }

    private List<AdmissionGridTO> convertToAdmissionGridTOList(
            final List<Admission> admissionList) {
        List<AdmissionGridTO> admissionGridTOList = new ArrayList<AdmissionGridTO>();

        for (final Admission admission : admissionList) {
            final Season season = seasonDAO.findSeason(admission.getSeasonId());
            admissionGridTOList.add(AdmissionConverter.convertToAdmissionGridTO(
                    admission, season));
        }

        return admissionGridTOList;
    }

    private List<MatchGridTO> convertToMatchGridTOList(final List<Match> matchList) {
        List<MatchGridTO> matchGridTOList = new ArrayList<MatchGridTO>();

        for (final Match match : matchList) {
            final Season season = seasonDAO.findSeason(match.getSeasonId());
            final Person player1 = personDAO.findPerson(match.getPlayer1Id());
            final Person player2 = personDAO.findPerson(match.getPlayer2Id());
            String finalScore = scoreCalculationService.calculateFinalScore(
                    match.getId(), season, roundDAO.getAllRoundsForMatch(match.getId()));
            matchGridTOList.add(MatchConverter.convertToMatchGridTO(
                    match, season, player1, player2, finalScore));
        }

        return matchGridTOList;
    }

	@Override
	public List<PersonGridTO> getPersonListByScore(Long seasonId) {
		
		HashMap map = this.personDAO.getPersonScoreListForSeason(seasonId);
		ArrayList<PersonGridTO> persons = new ArrayList<PersonGridTO>();
		
		Set set = map.entrySet();
		Iterator it = set.iterator();
		
		while (it.hasNext()) {
			Map.Entry me = (Map.Entry) it.next();
			
			PersonGridTO p = PersonConverter.convertToPersonGridTO((Person) me.getKey());
			p.setScore((int) me.getValue());
			persons.add(p);
		}
		
		Collections.sort(persons, new Comparator<PersonGridTO>() {
			
			@Override
			public int compare(PersonGridTO o1, PersonGridTO o2) {
				
				if (o1.getScore() == o2.getScore()) {
					return 0;
				}
				
				return o1.getScore() > o2.getScore() ? -1 : 1;
			}
		});
		
		return persons;
	}
}
